package com.jinglin.web.controller;

import com.aliyun.oss.model.OSSObject;
import com.jinglin.component.RedisComponent;
import com.jinglin.controller.ABaseController;
import com.jinglin.entity.config.AppConfig;
import com.jinglin.entity.constants.Constants;
import com.jinglin.entity.dto.SysSettingDto;
import com.jinglin.entity.dto.TokenUserInfoDto;
import com.jinglin.entity.dto.UploadingFileDto;
import com.jinglin.entity.dto.VideoPlayInfoDto;
import com.jinglin.entity.enums.ResponseCodeEnum;
import com.jinglin.entity.po.VideoInfoFile;
import com.jinglin.entity.vo.ResponseVO;
import com.jinglin.exception.BusinessException;
import com.jinglin.service.VideoInfoFileService;
import com.jinglin.utils.OssUtils;
import com.jinglin.web.annotation.GlobalInterceptor;
import org.apache.commons.io.FileUtils;
import org.apache.coyote.Response;
import org.apache.ibatis.annotations.Param;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.*;

@RestController
@RequestMapping("/file")
public class FileController extends ABaseController {
    @Resource
    private OssUtils ossUtils;
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private AppConfig appConfig;
    @Autowired
    private VideoInfoFileService videoInfoFileService;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Value("${exchange.video.play}")
    private String playExchange;
    @Value("${key.video.play}")
    private String playRoutingKey;


    @RequestMapping("/uploadImage")
    @GlobalInterceptor(checkLogin = true)
    public ResponseVO uploadImage(@NotNull MultipartFile file, @NotNull Boolean createThumbnail) {
        String s = ossUtils.uploadImage(file, "easylive1");
        return getSuccessResponseVO(s);
    }

    @RequestMapping("/getResource")
    public void getResource(@Param("sourceName") String sourceName, HttpServletResponse response) throws IOException {
        OSSObject ossObject = ossUtils.getObject("easylive1", sourceName);
        writeInputStreamToResponse(ossObject.getObjectContent(), response);
        response.setContentType("application/octet-stream");
    }

    @RequestMapping("/preUploadVideo")
    @GlobalInterceptor(checkLogin = true)
    public ResponseVO preUploadVideo(@NotEmpty String fileName, @NotNull Integer chunks) {
        TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto();
        String uploadId = redisComponent.savePreVideoFileInfo(tokenUserInfoDto.getUserId(), fileName, chunks);
        return getSuccessResponseVO(uploadId);
    }

    @RequestMapping("/uploadVideo")
    @GlobalInterceptor(checkLogin = true)
    public ResponseVO uploadVideo(@NotNull MultipartFile chunkFile, @NotNull Integer chunkIndex, @NotEmpty String uploadId) throws IOException {
        TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto();
        //从redis里面拿刚刚预上传的文件信息，查看是否存在。
        UploadingFileDto fileDto = redisComponent.getUploadFileDto(tokenUserInfoDto.getUserId(), uploadId);
        if (fileDto == null) {
            throw new BusinessException("文件不存在！！请重新上传");
        }
        // 获取系统设置
        SysSettingDto sysSettingDto = redisComponent.getSysSettingDto();
        // 这个filesize会随着分片的上传，累加。直到整个文件上传完毕
        if (fileDto.getFileSize() > sysSettingDto.getVideoSize() * Constants.MB_SIZE) {
            throw new BusinessException("文件超过大小限制！！请重新上传");
        }
        // 如果当前的分片索引-1 大于当前已经传送的文件的索引  或者 分片索引大于文件的最大索引-1 则参数错误
        if ((chunkIndex - 1) > fileDto.getChunkIndex() || chunkIndex > fileDto.getChunks() - 1) {
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        String tempDir = appConfig.getProjectFolder() + "/" + Constants.FILE_FOLDER + Constants.FILE_FOLDER_TEMP + fileDto.getFilePath();
        File tempFolder = new File(tempDir);
        if (!tempFolder.exists()) {
            tempFolder.mkdirs();
        }
        String folder = Constants.FILE_FOLDER_TEMP + fileDto.getFilePath();
        String chunkPath = folder + "/" + chunkIndex;

        File targetFile = new File(appConfig.getProjectFolder() + "/" + Constants.FILE_FOLDER + chunkPath);
        chunkFile.transferTo(targetFile);
        // 更新redis里面的文件信息。（每增加一个切片都要更新一次）
        fileDto.setChunkIndex(chunkIndex);
        // 累加
        fileDto.setFileSize(fileDto.getFileSize() + chunkFile.getSize());
        redisComponent.updateUploadFileDto(tokenUserInfoDto.getUserId(), fileDto);
        return getSuccessResponseVO(null);
    }

    @RequestMapping("/delUploadVideo")
    @GlobalInterceptor(checkLogin = true)
    public ResponseVO delUploadVideo(@NotEmpty String uploadId) throws IOException {
        TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto();
        UploadingFileDto uploadFileDto = redisComponent.getUploadFileDto(tokenUserInfoDto.getUserId(), uploadId);
        if (uploadFileDto == null) {
            throw new BusinessException("文件不存在请重新上传");
        }
        // 先从redis中删除文件上传信息
        redisComponent.delVideoFileInfo(tokenUserInfoDto.getUserId(), uploadId);
        File dir = new File(appConfig.getProjectFolder() + "/" + Constants.FILE_FOLDER_TEMP + uploadFileDto.getFilePath());
        FileUtils.deleteDirectory(dir);
        return getSuccessResponseVO(null);
    }

    @GetMapping("/videoResource/{fileId}")
    public void videoResource(@PathVariable @NotEmpty String fileId, HttpServletResponse response) throws IOException {
        VideoInfoFile videoInfoFile = videoInfoFileService.getById(fileId);
        if (videoInfoFile == null) {
            throw new BusinessException("文件不存在");
        }
        String filePath = videoInfoFile.getFilePath();
        File file = new File(appConfig.getProjectFolder() + Constants.FILE_FOLDER + filePath + "/" + Constants.M3U8_NAME);
        InputStream inputStream = new FileInputStream(file);
        writeInputStreamToResponse(inputStream, response);
        // 保存视频播放数据。
        TokenUserInfoDto tokenUserInfoDto = getTokenInfoFromCookie();

        VideoPlayInfoDto videoPlayInfoDto = new VideoPlayInfoDto();
        videoPlayInfoDto.setVideoId(videoInfoFile.getVideoId());
        videoPlayInfoDto.setFileIndex(videoInfoFile.getFileIndex());
        if (tokenUserInfoDto !=null ){
            // 非空时，证明处于登录状态。登录的时候保存历史观看数据
            videoPlayInfoDto.setUserId(tokenUserInfoDto.getUserId());
        }
        // 加入队列()
        rabbitTemplate.convertAndSend(playExchange,playRoutingKey,videoPlayInfoDto);
        redisComponent.addVideoPlay(videoPlayInfoDto);


    }
    @GetMapping("/videoResource/{fileId}/{ts}")
    public void videoResourceTs(@PathVariable @NotEmpty String fileId,@PathVariable @NotEmpty String ts, HttpServletResponse response) throws IOException {
        VideoInfoFile videoInfoFile = videoInfoFileService.getById(fileId);
        String filePath = videoInfoFile.getFilePath();
        File file = new File(appConfig.getProjectFolder() + Constants.FILE_FOLDER + filePath + "/" + ts);
        InputStream inputStream = new FileInputStream(file);
        writeInputStreamToResponse(inputStream, response);
    }
    protected void writeInputStreamToResponse(InputStream inp, HttpServletResponse response) throws IOException {
        try (inp; OutputStream out = response.getOutputStream()) {
            byte[] bytes = new byte[1024];
            int bytesRead;
            while ((bytesRead = inp.read(bytes)) != -1) {
                out.write(bytes, 0, bytesRead);
            }
        }
    }

}
